package com.db.stockexchange.client.ui;

import java.awt.BorderLayout;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelListener;
import javax.swing.JTable;
import javax.swing.table.TableModel;
import javax.swing.JButton;

import com.db.stockexchange.client.ClientPresenter;
import com.db.stockexchange.client.Stock;
import com.db.stockexchange.client.StockOperation;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import java.util.Random;

import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;

public class MainFrame extends JFrame implements MainView {
	private static final long serialVersionUID = -991932784758732632L;
	
	private JPanel contentPane;
	private JTable table;
	
	private ClientPresenter presenter;
	private JTextField txtTicker;
	private JTextField txtShareNumber;
	private JTextField txtPrice;
	
	private JCheckBox chbUseBestMarketPrice;
	private JComboBox<StockOperation> cmbOperation;
	private JButton btnTurboMode;

	/**
	 * Create the frame.
	 */
	public MainFrame() {		
		presenter = new ClientPresenter(this);
		
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setBounds(100, 100, 687, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		table = new JTable();
		table.setModel(new StockTableModel(presenter.getStocks()));
		table.getColumnModel().getColumn(0).setResizable(false);
		table.getColumnModel().getColumn(0).setPreferredWidth(35);
		table.getColumnModel().getColumn(0).setMinWidth(25);
		table.getColumnModel().getColumn(0).setMaxWidth(75);
		table.getColumnModel().getColumn(1).setPreferredWidth(85);
		table.getColumnModel().getColumn(1).setResizable(false);
		table.getColumnModel().getColumn(1).setMinWidth(35);
		table.getColumnModel().getColumn(2).setResizable(false);
		table.getColumnModel().getColumn(2).setPreferredWidth(85);
		table.getColumnModel().getColumn(2).setMinWidth(35);
		table.getColumnModel().getColumn(3).setPreferredWidth(85);
		table.getColumnModel().getColumn(3).setResizable(false);
		table.getColumnModel().getColumn(3).setMinWidth(35);
		table.getColumnModel().getColumn(4).setPreferredWidth(85);
		table.getColumnModel().getColumn(4).setResizable(false);
		table.getColumnModel().getColumn(4).setMinWidth(35);
		table.getColumnModel().getColumn(5).setPreferredWidth(85);
		table.getColumnModel().getColumn(5).setResizable(false);
		table.getColumnModel().getColumn(5).setMinWidth(35);
		contentPane.add(new JScrollPane(table), BorderLayout.CENTER);
		
		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.SOUTH);
		panel_1.setLayout(new MigLayout("", "[50px:175px,growprio 25,fill][50px:175px,growprio 25,fill][50px:175px,growprio 25,fill][50px:175px,growprio 50,fill][right]", "[][][]"));
		
		JLabel lblTicker = new JLabel("Ticker");
		panel_1.add(lblTicker, "flowy,cell 0 0,alignx center,aligny top");
		
		JLabel lblOperation = new JLabel("Operation");
		panel_1.add(lblOperation, "flowy,cell 1 0,alignx left,aligny top");
		
		JLabel lblShareNumber = new JLabel("Share number");
		panel_1.add(lblShareNumber, "flowy,cell 2 0,alignx center,aligny top");
		
		JLabel lblPrice = new JLabel("Price");
		panel_1.add(lblPrice, "flowy,cell 3 0,alignx center,aligny top");
		
		txtTicker = new JTextField();
		panel_1.add(txtTicker, "cell 0 1,aligny top");
		txtTicker.setColumns(10);
		
		cmbOperation = new JComboBox<StockOperation>();
		cmbOperation.setModel(new DefaultComboBoxModel<StockOperation>(StockOperation.values()));
		panel_1.add(cmbOperation, "cell 1 1,alignx center,aligny top");
		
		txtShareNumber = new JTextField();
		panel_1.add(txtShareNumber, "cell 2 1,aligny top");
		txtShareNumber.setColumns(10);
		
		txtPrice = new JTextField();
		panel_1.add(txtPrice, "cell 3 1,aligny top");
		txtPrice.setColumns(10);
		
		JButton btnNewOrder = new JButton("Add Order");
		panel_1.add(btnNewOrder, "cell 4 1,growx,aligny top");
		
		chbUseBestMarketPrice = new JCheckBox("Use market price");
		chbUseBestMarketPrice.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				txtPrice.setEnabled(!chbUseBestMarketPrice.isSelected());
			}
		});
		panel_1.add(chbUseBestMarketPrice, "cell 3 2,grow");
		
		btnTurboMode = new JButton("Turbo Mode");
		btnTurboMode.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				new SwingWorker<String, String>() {
					@Override
					protected String doInBackground() throws Exception {
						Random random = new Random();
						for (int i=0; i<100; i++) {
							String ticker = null;
							int n = random.nextInt(4);
							switch (n) {
								case 0:ticker = "IBM"; break;
								case 1:ticker = "APPLE"; break;
								case 2:ticker = "MSFT"; break;
								case 3:ticker = "BTR"; break;
							}
							int op = random.nextInt(2);
							int shareNumber = (random.nextInt(3) + 5) * 10;
							float price = (random.nextInt(10) + 1) * 10;
							
							MainFrame.this.presenter.newOrder(ticker, StockOperation.byIndex(op), shareNumber, price);
							
							try {
								Thread.sleep(100);
							} catch (InterruptedException e) { }
						}
						
						return null;
					}
				}.execute();
			}
		});
		panel_1.add(btnTurboMode, "cell 4 2,growx,aligny top");
		btnNewOrder.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				StockOperation op = (StockOperation)cmbOperation.getSelectedItem();
				int shareNumber;
				float price = Float.NaN;
				
				try {
					shareNumber = Integer.parseInt(txtShareNumber.getText());
					if (shareNumber <= 0)
						throw new NumberFormatException();
				} catch (NumberFormatException ex) {
					JOptionPane.showMessageDialog(contentPane, "Number of shares must be positive real value");
					return;
				}
				
				if (!chbUseBestMarketPrice.isSelected()) {
					try {
						price = Float.parseFloat(txtPrice.getText());
						if (price <= 0)
							throw new NumberFormatException();
					} catch (NumberFormatException ex) {
						JOptionPane.showMessageDialog(contentPane, "Price must be positive real value");
						return;
					}

					MainFrame.this.presenter.newOrder(txtTicker.getText(), op, shareNumber, price);
				} else {
					MainFrame.this.presenter.newOrder(txtTicker.getText(), op, shareNumber);
				}
			}
		});
		
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				presenter.close();
			}
		});
	}

	@Override
	public void refreshStockList() {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				table.setModel(new StockTableModel(presenter.getStocks()));
			}
		});
	}

	@Override
	public void showRejectReason(final String reason) {
		
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				JOptionPane.showMessageDialog(contentPane, reason);
			}
		});		
	}
	
	public void showLoginDialog() {
		try {
			LoginDialog dialog = new LoginDialog(presenter, this);
			dialog.setModal(true);
			dialog.setAlwaysOnTop(true);
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			dialog.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public class StockTableModel implements TableModel {
		 
        private List<Stock> stocks;
 
        public StockTableModel(List<Stock> stocks) {
            this.stocks = stocks;
        }
 
        public void addTableModelListener(TableModelListener listener) {
        }
 
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }
 
        public int getColumnCount() {
            return 6;
        }
 
        public String getColumnName(int columnIndex) {
            switch (columnIndex) {
            case 0:
                return "Id";
            case 1:
                return "Ticker";
            case 2:
                return "Operation";
            case 3:
                return "Share number";
            case 4:
            	return "Price";
            case 5:
            	return "Status";
            }
            return "";
        }
 
        public int getRowCount() {
            return stocks.size();
        }
 
        public Object getValueAt(int rowIndex, int columnIndex) {
            Stock stock = stocks.get(rowIndex);
            switch (columnIndex) {
            case 0:
                return stock.getId();
            case 1:
                return stock.getName();
            case 2:
                return stock.getOperation();
            case 3:
                return stock.getShareNumber();
            case 4:
                return stock.isUseBestMarketPrice() ? "MARKET" : stock.getPrice();
            case 5:
                return stock.getState();
            }
            return "";
        }

		@Override
		public boolean isCellEditable(int rowIndex, int columnIndex) {
			return false;
		}

		@Override
		public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
			
		}

		@Override
		public void removeTableModelListener(TableModelListener l) {
			
		} 
    }
}
